package org.wheel.plugins.toolkit.sql.helper;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import lombok.Getter;
import org.wheel.plugins.toolkit.sql.entity.AliasEntry;
import org.wheel.plugins.toolkit.sql.entity.FieldKey;
import org.wheel.plugins.toolkit.util.ReverseLinkedHashMap;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 全局别名注册器 – 单例
 */
public final class AliasRegistry {

//    private static final AliasRegistry INSTANCE = new AliasRegistry();

    // 保证插入顺序且线程安全，不需要特别关注高并发
    @Getter
    private final Map<Class<?>, List<AliasEntry>> entityAliases = Collections.synchronizedMap(new ReverseLinkedHashMap<>());
    /** 字段键 → 唯一别名 */
    @Getter
    private final ReverseLinkedHashMap<FieldKey, String> field2Alias = new ReverseLinkedHashMap<>();
    /**
     * 因为可能SQL会有自关联表或者关联多个相同的表，所以 key 存储别名
     * key → 别名
     * value → 表名
     */
    private final ReverseLinkedHashMap<String, String> alias2Table = new ReverseLinkedHashMap<>();

    private final AtomicInteger seq = new AtomicInteger(1); // t2/t3...

//    private AliasRegistry() {}

//    public static AliasRegistry getInstance() {
//        return INSTANCE;
//    }

    public String nextAlias() {
        return "t" + seq.getAndIncrement();
    }

    /**
     * 注册别名
     * @param entityClass
     * @param alias
     */
    public void register(Class<?> entityClass, String alias) {
        // 第一次注册的一定是主表
        boolean isMain = false;
        if(entityAliases.isEmpty()){
            isMain = true;
        }
        entityAliases.computeIfAbsent(entityClass, k -> CollUtil.newArrayList())
                .add(AliasEntry.builder().alias(alias).lastUsed(System.currentTimeMillis()).isMain(false).build());
        // 反向映射所有字段
        for (java.lang.reflect.Field f : ReflectUtil.getFields(entityClass)) {
            field2Alias.put(new FieldKey(entityClass, f.getName()), alias);
        }
    }

    /**
     * 替换别名
     */
    public void replaceAlias(Class<?> entityClass, String alias) {
        List<AliasEntry> list = this.entityAliases.get(entityClass);
        if(!list.isEmpty()){
            AliasEntry last = list.get(list.size()-1);
            last.setAlias(alias);
            last.setLastUsed(System.currentTimeMillis());
        }
    }

    /**
     * 别名选择算法 –「最近使用 + 主表兜底」
     * 根据实体类 + 使用场景，自动选择最优别名
     * 场景：leftCol 或 rightCol 的实体类
     * @param entityClass
     * @param joinIndex
     * @return
     */
    public String resolveAlias(Class<?> entityClass, int joinIndex) {
        for (Map.Entry<Class<?>, List<AliasEntry>> entry : entityAliases.entrySet()) {
            if (entry.getKey().getName().equals(entityClass.getName())) {
                List<AliasEntry> aliases = entry.getValue();
                if (joinIndex < -1 || joinIndex >= aliases.size()) {
                    throw new IllegalArgumentException("索引越界");
                }
                return joinIndex == -1 ? aliases.get(0).getAlias() : aliases.get(joinIndex).getAlias();
            }
        }
        throw new IllegalArgumentException("实体 " + entityClass.getSimpleName() + " 未注册别名");
    }

    /**
     * 是否注册了 class实体
     * @param entityClass
     * @return
     */
    public boolean isRegister(Class<?> entityClass){
        return entityClass!=null && entityAliases.keySet().stream().anyMatch(k->k.getName().equals(entityClass.getName()));
    }

    /**
     * 别名选择算法 –「最近使用 + 主表兜底」
     * 根据实体类 + 使用场景，自动选择最优别名
     * 场景：leftCol 或 rightCol 的实体类
     * @param entityClass
     * @return
     */
    public String resolveAlias(Class<?> entityClass) {
        List<AliasEntry> list = entityAliases.get(entityClass);
        if (CollUtil.isEmpty(list)) {
            throw new IllegalArgumentException("实体未注册别名");
        }

        // 1. 只注册一次 → 直接用
        if (list.size() == 1) {
            return list.get(0).getAlias();
        }

        // 2. 多个 → 按「最近使用」降序
        AliasEntry best = list.stream()
                .max(Comparator.comparingLong(AliasEntry::getLastUsed))
                .orElseThrow();

        // 3. 主表兜底（isMain = true）
        if (best.isMain()) {
            return best.getAlias();
        }

        // 4. 仍然模糊 → 延迟注入（见下方）
        return best.getAlias(); // 先返回最近使用的，后续链式内部注入
    }

    /**
     * 为了实体表名直接写SQL准备的。
     * 注册别名
     * @param tableName 表名
     * @param alias 别名
     */
    public void register(String tableName, String alias){
        alias2Table.put(alias, tableName);
    }

    /**
     * 替换表名最近一次注册的别名
     */
    public void replaceAlias(String tableName, String alias) {
        // 反向遍历：ReverseLinkedHashMap 逆序即“最近插入在最后”
        for (Map.Entry<String, String> e : alias2Table.reverseEntryList()) {
            if (e.getValue().equalsIgnoreCase(tableName)) {
                // 找到该表名最近一次出现的条目，只改 key（别名）
                alias2Table.remove(e.getKey());
                alias2Table.put(alias, tableName);
                return;
            }
        }
        // 如果表名从未注册过，可做两种策略：1. 忽略  2. 抛异常
        // 这里采用“静默返回”，与 Class 版本风格保持一致
    }

    /**
     * 根据表名解析最优别名（最近使用 + 主表兜底）
     */
    public String resolveAlias(String tableName) {
        // 1. 只出现一次 → 直接返回
        long cnt = alias2Table.values().stream()
                .filter(t -> t.equalsIgnoreCase(tableName))
                .count();
        if (cnt == 1) {
            return alias2Table.entrySet().stream()
                    .filter(e -> e.getValue().equalsIgnoreCase(tableName))
                    .findFirst()
                    .map(Map.Entry::getKey)
                    .orElse(null);
        }

        // 2. 多次出现 → 取“最近一次”插入的（ReverseLinkedHashMap 逆序遍历即可）
        for (Map.Entry<String, String> e : alias2Table.reverseEntryList()) {
            if (e.getValue().equalsIgnoreCase(tableName)) {
                return e.getKey();
            }
        }

        // 3. 从未注册
        throw new IllegalArgumentException("表名 " + tableName + " 未注册别名");
    }
}